#include "FLOAT.h"
#include <string.h>

FLOAT F_mul_F(FLOAT a, FLOAT b) {
	//nemu_assert(0);
	//return 0;
	long long x = (long long)a * (long long)b;
	return (FLOAT)(x >> 16);
}

FLOAT F_div_F(FLOAT a, FLOAT b) {
	/* Dividing two 64-bit integers needs the support of another library
	 * `libgcc', other than newlib. It is a dirty work to port `libgcc'
	 * to NEMU. In fact, it is unnecessary to perform a "64/64" division
	 * here. A "64/32" division is enough.
	 *
	 * To perform a "64/32" division, you can use the x86 instruction
	 * `div' or `idiv' by inline assembly. We provide a template for you
	 * to prevent you from uncessary details.
	 *
	 *     asm volatile ("??? %2" : "=a"(???), "=d"(???) : "r"(???), "a"(???), "d"(???));
	 *
	 * If you want to use the template above, you should fill the "???"
	 * correctly. For more information, please read the i386 manual for
	 * division instructions, and search the Internet about "inline assembly".
	 * It is OK not to use the template above, but you should figure
	 * out another way to perform the division.
	 */

	// nemu_assert(0);
	// return 0;
	FLOAT res = (a << 16) / b;
	return res;
	// int qwq = 1;
	// if(a < 0) { qwq *= -1; a = -a; }
	// if(b < 0) { qwq *= -1; b = -b; }
	// // 整数部分：a/b
	// FLOAT x = (a / b);
	// // 小数部分：
	// // for 每一位小数：		x = x * 10 + 1 ? 0 : 还有
	// a = a % b;
	// int i;
	// for(i = 0; i < 16; i++){
	// 	a <<= 1; x <<= 1;
	// 	if(a >= b){	//（a<<i / b） >= 1时
	// 		a -= b; x++;
	// 	}
	// }
	// return x * qwq;
}

FLOAT f2F(float a) {
	/* You should figure out how to convert `a' into FLOAT without
	 * introducing x87 floating point instructions. Else you can
	 * not run this code in NEMU before implementing x87 floating
	 * point instructions, which is contrary to our expectation.
	 *
	 * Hint: The bit representation of `a' is already on the
	 * stack. How do you retrieve it to another variable without
	 * performing arithmetic operations on it directly?
	 */

	//nemu_assert(0);
	//return 0;
	int arr[1];
	//不直接执行算术运算的情况下将其取出
	memcpy((void*)arr, (void*)&a, 4);
	int f = *arr;

	int sign = f >> 31;
	int exp = f >> 23;
	exp &= 0xff;

	FLOAT frac = f & 0x7fffff;
	if(exp != 0) frac = frac + (1 << 23);
	else exp = 1;
	exp -= 150;
	if(exp + 16 > 0) frac <<= exp + 16;
	else if (exp + 16 < 0){
		frac >>= -(exp + 16);
	}

	if(sign == 0) return frac;
	else return -frac;
}

FLOAT Fabs(FLOAT a) {
	// nemu_assert(0);
	// return 0;
	// int sign = ((a & 0x80000000) >> 31) & 0x1;
	// int flag = sign ^ 0x1;
	// int mask = ~flag + 1;
	// FLOAT result = (mask & (~a + 1))|((~mask) & a);
	// return result;
	if (a >> 31) 
		return 1;
	else
		return -1;
}

/* Functions below are already implemented */

FLOAT sqrt(FLOAT x) {
	FLOAT dt, t = int2F(2);

	do {
		dt = F_div_int((F_div_F(x, t) - t), 2);
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

FLOAT pow(FLOAT x, FLOAT y) {
	/* we only compute x^0.333 */
	FLOAT t2, dt, t = int2F(2);

	do {
		t2 = F_mul_F(t, t);
		dt = (F_div_F(x, t2) - t) / 3;
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

